import { Header } from './common';
import { DomHandler } from './../utils';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { Component, ElementRef, AfterViewInit, AfterViewChecked, OnDestroy, Input, Output, EventEmitter, Renderer, ContentChild } from '@angular/core';

@Component({
    selector: 'mpj-dialog',
    styleUrls: [
        './msg.scss'
    ],
    template: `
        <div class="layout-column kds-dialog" [ngClass]="{'ui-dialog ui-widget-content':true,'ui-dialog-rtl':rtl,'ui-dialog-draggable':draggable,'center-dialog':tipCenter}" 
            [style.display]="visible ? 'flex' : 'none'" [style.width.px]="width" [style.height.px]="height" (mousedown)="moveOnTop()">
            <md-toolbar *ngIf="showHeader" [ngClass]="getHeaderClass()"
                (mousedown)="initDrag($event)" (mouseup)="endDrag($event)">
                <ng-content select="header"></ng-content>
            </md-toolbar>
            <div class="dialog-content ui-dialog-content ui-widget-content flex layout" [ngClass]="getClass()" [style.height.px]="contentHeight">
                <ng-content></ng-content>
            </div>
            <ng-content select="footer"></ng-content>
            <div *ngIf="resizable" class="ui-resizable-handle ui-resizable-se ui-icon ui-icon-gripsmall-diagonal-se" style="z-index: 90;"
                (mousedown)="initResize($event)"></div>
        </div>
    `,
    providers: [DomHandler]
})
export class Dialog implements AfterViewInit, AfterViewChecked, OnDestroy {

    @Input() header: string;

    @Input() layout: string;

    @Input() headerClass: string;

    @Input() showHeader: boolean = false;

    @Input() tipCenter: boolean = false;

    @Input() draggable: boolean = false;

    @Input() resizable: boolean = false;

    @Input() minWidth: number = 150;

    @Input() minHeight: number = 150;

    @Input() width: any;

    @Input() height: any;

    @Input() contentHeight: any;

    @Input() modal: boolean;

    @Input() showEffect: string;

    @Input() closeOnEscape: boolean = true;

    @Input() closeOnMask: boolean = true;

    @Input() rtl: boolean;

    @Input() closable: boolean = true;

    @Input() responsive: boolean;

    @ContentChild(Header) headerFacet;

    @Output() onBeforeShow: EventEmitter<any> = new EventEmitter();

    @Output() onAfterShow: EventEmitter<any> = new EventEmitter();

    @Output() onBeforeHide: EventEmitter<any> = new EventEmitter();

    @Output() onAfterHide: EventEmitter<any> = new EventEmitter();

    @Output() visibleChange: EventEmitter<any> = new EventEmitter();

    _visible: boolean;

    dragging: boolean;

    documentDragListener: any;

    resizing: boolean;

    documentResizeListener: any;

    documentResizeEndListener: any;

    documentResponsiveListener: any;

    documentEscapeListener: any;

    lastPageX: number;

    lastPageY: number;

    mask: any;

    shown: boolean;

    contentContainer: any;

    positionInitialized: boolean;

    constructor(private el: ElementRef, private domHandler: DomHandler, private renderer: Renderer) { }
    getClass() {
        if (this.layout) {
            return this.layout;
        }
    }
    getHeaderClass() {
        if (this.headerClass) {
            return this.headerClass;
        }
    }
    @Input() get visible(): boolean {
        return this._visible;
    }

    set visible(val: boolean) {
        this._visible = val;
        if (this._visible) {
            this.onBeforeShow.emit({});

            if (!this.positionInitialized) {
                this.center();
                this.positionInitialized = true;
            }

            this.el.nativeElement.children[0].style.zIndex = ++DomHandler.zindex;
            if (this.showEffect == 'fade') {
                this.domHandler.fadeIn(this.el.nativeElement.children[0], 250);
            }

            if (this.showEffect == 'scale') {
                this.domHandler.scaleIn(this.el.nativeElement.children[0], 250);
            }

            if (this.showEffect == "slideLeft") {
                this.domHandler.slideLeft(this.el.nativeElement.children[0], 250);
            }
            this.shown = true;
        }

        if (this.modal) {
            if (this._visible)
                this.enableModality();
            else
                this.disableModality();
        }
    }

    ngAfterViewInit() {
        this.contentContainer = this.domHandler.findSingle(this.el.nativeElement, '.ui-dialog-content');

        if (this.draggable) {
            this.documentDragListener = this.renderer.listenGlobal('body', 'mousemove', (event) => {
                this.onDrag(event);
            });
        }

        if (this.resizable) {
            this.documentResizeListener = this.renderer.listenGlobal('body', 'mousemove', (event) => {
                this.onResize(event);
            });

            this.documentResizeEndListener = this.renderer.listenGlobal('body', 'mouseup', (event) => {
                if (this.resizing) {
                    this.resizing = false;
                }
            });
        }

        if (this.responsive) {
            this.documentResponsiveListener = this.renderer.listenGlobal('window', 'resize', (event) => {
                this.center();
            });
        }

        if (this.closeOnEscape && this.closable) {
            this.documentEscapeListener = this.renderer.listenGlobal('body', 'keydown', (event) => {
                if (event.which == 27) {
                    if (this.el.nativeElement.children[0].style.zIndex == DomHandler.zindex)  {
                        this.hide(event);
                    }
                }
            });
        }
    }

    ngAfterViewChecked() {
        if (this.shown) {
            this.onAfterShow.emit({});
            this.shown = false;
        }
    }

    center() {
        let container = this.el.nativeElement.children[0];
        let elementWidth = this.domHandler.getOuterWidth(container);
        let elementHeight = this.domHandler.getOuterHeight(container);
        if (elementWidth == 0 && elementHeight == 0) {
            container.style.visibility = 'hidden';
            container.style.display = 'block';
            elementWidth = this.domHandler.getOuterWidth(container);
            elementHeight = this.domHandler.getOuterHeight(container);
            container.style.display = 'none';
            container.style.visibility = 'visible';
        }
        let viewport = this.domHandler.getViewport();
        let x = (viewport.width - elementWidth) / 2;
        let y = (viewport.height - elementHeight) / 2;

        container.style.left = x + 'px';
        container.style.top = y + 'px';
    }

    enableModality() {
        if (!this.mask) {
            this.mask = document.createElement('div');
            this.mask.style.zIndex = this.el.nativeElement.children[0].style.zIndex - 1;
            this.domHandler.addMultipleClasses(this.mask, 'ui-widget-overlay ui-dialog-mask');
            document.body.appendChild(this.mask);
            //添加点击蒙层关闭dialog的事件
            if (this.modal && this.closeOnMask && this.closable) {
                this.renderer.listen(this.mask, "click", (event) => {
                    this.hide(event);
                });
            }
        }
    }

    disableModality() {
        if (this.mask) {
            document.body.removeChild(this.mask);
            this.mask = null;
        }
    }

    hide(event) {
        this.onBeforeHide.emit(event);
        this.visibleChange.emit(false);
        this.onAfterHide.emit(event);
        event.preventDefault();
    }

    moveOnTop() {
        this.el.nativeElement.children[0].style.zIndex = ++DomHandler.zindex;
    }

    initDrag(event) {
        if (this.draggable) {
            this.dragging = true;
            this.lastPageX = event.pageX;
            this.lastPageY = event.pageY;
        }
    }

    onDrag(event) {
        if (this.dragging) {
            let container = this.el.nativeElement.children[0];
            let deltaX = event.pageX - this.lastPageX;
            let deltaY = event.pageY - this.lastPageY;
            let leftPos = parseInt(container.style.left);
            let topPos = parseInt(container.style.top);

            container.style.left = leftPos + deltaX + 'px';
            container.style.top = topPos + deltaY + 'px';

            this.lastPageX = event.pageX;
            this.lastPageY = event.pageY;
        }
    }

    endDrag(event) {
        if (this.draggable) {
            this.dragging = false;
        }
    }

    initResize(event) {
        if (this.resizable) {
            this.resizing = true;
            this.lastPageX = event.pageX;
            this.lastPageY = event.pageY;
        }
    }

    onResize(event) {
        if (this.resizing) {
            let container = this.el.nativeElement.children[0];
            let deltaX = event.pageX - this.lastPageX;
            let deltaY = event.pageY - this.lastPageY;
            let containerWidth = this.domHandler.getOuterWidth(container);
            let contentHeight = this.domHandler.getHeight(this.contentContainer);
            let newWidth = containerWidth + deltaX;
            let newHeight = contentHeight + deltaY;

            if (newWidth > this.minWidth)
                container.style.width = newWidth + 'px';

            if (newHeight > this.minHeight)
                this.contentContainer.style.height = newHeight + 'px';

            this.lastPageX = event.pageX;
            this.lastPageY = event.pageY;
        }
    }

    ngOnDestroy() {
        this.disableModality();

        if (this.documentDragListener) {
            this.documentDragListener();
        }

        if (this.resizable) {
            this.documentResizeListener();
            this.documentResizeEndListener();
        }

        if (this.responsive) {
            this.documentResponsiveListener();
        }

        if (this.closeOnEscape && this.closable) {
            this.documentEscapeListener();
        }
    }

}

@NgModule({
    imports: [
        CommonModule,
        FormsModule
    ],
    declarations: [Dialog],
    exports: [Dialog],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class DialogModule { }